package com.xbongbong.paas.help;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.formula.service.FunctionService;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.ext.ConditionsEntityExt;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.ConditionEnum;
import com.xbongbong.paas.enums.DateTimeEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author: wufeng
 * @date: 2018/9/18 13:55
 * @desrcption: 根据条件判断值
 */
@Component
public class CompareValueByConditionHelp {

    private static final Logger LOGGER = LoggerFactory.getLogger(CompareValueByConditionHelp.class);

    @Resource
    private FunctionService functionService;

    /**
     * 判断值是否符合条件
     * @param condition
     * @return
     */
    public boolean compareValueByCondition(ConditionsEntityExt condition, Object value) throws Exception {
        ConditionEnum conditionEnum = ConditionEnum.getConditionEnum(condition.getSymbol());
        if (conditionEnum == null) {
            return false;
        }
        boolean result = false;
        if(value == null && !Objects.equals(conditionEnum, ConditionEnum.EMPTY)){
            return false;
        }
        // 日期字段动态值进行时间转换
        if (Objects.equals(condition.getSymbol(), ConditionEnum.DYNAMIC.getSymbol()) && Objects.equals(condition.getFieldType(), FieldTypeEnum.DATETIME.getType())) {
            EsUtil.getValueByDate(condition);
        }
        List<Object> conditions = condition.getValue();
        String conditionString = Objects.toString(conditions, "");
        switch (conditionEnum){
            // 多选也可等于
            case EQUAL :
                if(value instanceof List){
                    List<Object> list = JSONArray.parseArray(JSON.toJSONString(value), Object.class);
                    if (CollectionsUtil.isEmpty(list) || !Objects.equals(list.size(), conditions.size())) {
                        break;
                    }
                    boolean temp = true;
                    for (Object object : list) {
                        if(!conditionString.contains(object.toString())) {
                            temp = false;
                            break;
                        }
                    }
                    result = temp;
                } else {
                    FieldTypeEnum dateFieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                    if (Objects.nonNull(dateFieldTypeEnum) && Objects.equals(dateFieldTypeEnum.getEsalias(), FieldTypeEnum.DATETIME.getEsalias())) {
                        // 日期字段的相等需要按照范围处理
                        Long conditionValue = Long.valueOf(Objects.toString(conditions.get(0)));
                        Long dataValue = Long.valueOf(Objects.toString(value));
                        if (Objects.equals(condition.getDateType(), DateTimeEnum.TIME.getType())) {
                            Long startOfDay = DateTimeUtil.getStartOfDay(conditionValue);
                            Long endOfDay = DateTimeUtil.getEndOfDay(conditionValue);
                            result = dataValue >= startOfDay && dataValue <= endOfDay;
                        } else if (Objects.equals(condition.getDateType(), DateTimeEnum.DATETIME.getType())) {
                            Long startOfMinute = DateTimeUtil.getStartOfMinute(conditionValue);
                            Long endOfMinute = DateTimeUtil.getEndOfMinute(conditionValue);
                            result = dataValue >= startOfMinute && dataValue <= endOfMinute;
                        }
                    } else {
                        result = equals(value, conditions.get(0));
                    }
                }
                break;
            case NOEQUAL:
                FieldTypeEnum attrFieldTypeEnum = FieldTypeEnum.getFieldTypeEnum(condition.getFieldType());
                if (Objects.nonNull(attrFieldTypeEnum) && Objects.equals(attrFieldTypeEnum.getEsalias(), FieldTypeEnum.DATETIME.getEsalias())) {
                    Long conditionValue = Long.valueOf(Objects.toString(conditions.get(0)));
                    Long dataValue = Long.valueOf(Objects.toString(value));
                    // 日期字段的不相等需要按照范围处理
                    if (Objects.equals(condition.getDateType(), DateTimeEnum.TIME.getType())) {
                        Long startOfDay = DateTimeUtil.getStartOfDay(conditionValue);
                        Long endOfDay = DateTimeUtil.getEndOfDay(conditionValue);
                        result = dataValue < startOfDay || dataValue > endOfDay;
                    } else if (Objects.equals(condition.getDateType(), DateTimeEnum.DATETIME.getType())) {
                        Long startOfMinute = DateTimeUtil.getStartOfMinute(conditionValue);
                        Long endOfMinute = DateTimeUtil.getEndOfMinute(conditionValue);
                        result = dataValue < startOfMinute || dataValue > endOfMinute;
                    }
                } else {
                    result = noEquals(value, conditions.get(0));
                }
                break;
            case EMPTY:
                if (value instanceof List) {
                    result = CollectionUtils.isEmpty(JSON.parseArray(JSON.toJSONString(value)));
                } else if (value instanceof Map && Objects.equals(condition.getFieldType(), FieldTypeEnum.ADDRESS.getType())) {
                    JSONObject addressObj = JSON.parseObject(JSON.toJSONString(value));
                    String province = addressObj.getString(PaasConstant.PROVINCE);
                    String city = addressObj.getString(PaasConstant.CITY);
                    String district = addressObj.getString(PaasConstant.DISTRICT);
                    String address = addressObj.getString(PaasConstant.ADDRESS);
                    result = StringUtils.isEmpty(province) && StringUtils.isEmpty(city) && StringUtils.isEmpty(district) && StringUtils.isEmpty(address);
                } else {
                    result = StringUtils.isEmpty(Objects.toString(value, ""));
                }
                break;
            case NOEMPTY:
                if (value instanceof List) {
                    result = CollectionUtils.isNotEmpty(JSON.parseArray(JSON.toJSONString(value)));
                } else if (value instanceof Map && Objects.equals(condition.getFieldType(), FieldTypeEnum.ADDRESS.getType())) {
                    JSONObject addressObj = JSON.parseObject(JSON.toJSONString(value));
                    String province = addressObj.getString(PaasConstant.PROVINCE);
                    String city = addressObj.getString(PaasConstant.CITY);
                    String district = addressObj.getString(PaasConstant.DISTRICT);
                    String address = addressObj.getString(PaasConstant.ADDRESS);
                    result = StringUtils.isNotEmpty(province) || StringUtils.isNotEmpty(city) || StringUtils.isNotEmpty(district) || StringUtils.isNotEmpty(address);
                } else {
                    result = StringUtils.isNotEmpty(Objects.toString(value, ""));
                }
                break;
            case INCLUDE:
                if(value instanceof List){
                    List<String> list = JSONArray.parseArray(JSON.toJSONString(value), String.class);
                    if (CollectionsUtil.isEmpty(list)) {
                        break;
                    }
                    Out:
                    for (Object object : conditions) {
                        for (String valueStr : list) {
                            if (Objects.equals(valueStr, object.toString())) {
                                result = true;
                                break Out;
                            }
                        }
                    }
                } else {
                    String valueString = Objects.toString(value, "");
                    for (Object object : conditions) {
                        if (valueString.contains(object.toString())) {
                            result = true;
                            break;
                        }
                    }
                }
                break;
            case ALLINCLUDE:
                result = allInclude(Objects.toString(value, ""), conditions);
                break;
            case LIKE:
                result = Objects.toString(value, "").contains(conditions.get(0).toString());
                break;
            case NOLIKE:
                result = !Objects.toString(value, "").contains(conditions.get(0).toString());
                break;
            case IN:
                result = in(value, conditions);
                break;
            case NOIN:
                result = noIn(value, conditions);
                break;
            case GREATEREQUAL:
                result = greaterEqual(value, conditions.get(0));
                break;
            case GREATERTHAN:
                result = greaterThan(value, conditions.get(0));
                break;
            case LESSEQUAL:
                result = lessEqual(value, conditions.get(0));
                break;
            case LESSTHAN:
                result = lessThan(value, conditions.get(0));
                break;
            case RANGE:
                result = range(Objects.toString(value, ""), conditions);
                break;
            case DYNAMIC:
                result = dynamic(Objects.toString(value, ""), conditions);
                break;
            default:
                break;
        }
        return result;
    }
    /**
     * 等于
     * @param value
     * @param value1
     * @return
     */
    private boolean equals(Object value, Object value1) throws Exception {
        if( value instanceof String) {
            return StringUtils.equals(value.toString(), value1.toString());
        }
        if (value instanceof Map) {
            JSONObject valueObj = JSON.parseObject(JSON.toJSONString(value));
            JSONObject value1Obj = JSON.parseObject(JSON.toJSONString(value1));
            return valueObj.equals(value1Obj);
        }
        return ((Boolean) functionService.expressRun(value +"==" + value1, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY))).booleanValue();
    }

    /**
     * 不等于
     * @param value
     * @param value1
     * @return
     */
    private boolean noEquals(Object value, Object value1) throws Exception {
        if( value instanceof String) {
            return !StringUtils.equals(value.toString(), value1.toString());
        }
        return ((Boolean)functionService.expressRun(value +"!=" + value1, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY))).booleanValue();
    }

    /**
     * 选择范围
     * @param value
     * @param value1
     * @return
     */
    private static boolean range(Object value, List<Object> value1) {
        // number类型比较大小，按最大类型Double比较
        boolean flag;
        try {
            double valueDouble = Double.valueOf(value.toString());
            double startDouble = Double.valueOf(value1.get(0).toString());
            double endDouble = Double.valueOf(value1.get(1).toString());
            flag = startDouble <= valueDouble && endDouble >= valueDouble;
        } catch (NumberFormatException e) {
            flag = false;
        }
        return flag;
    }

    private static boolean dynamic(Object value, List<Object> value1) {
        boolean flag;
        try {
            long valueLong = Long.parseLong(value.toString());
            long startLong = Long.parseLong(value1.get(0).toString());
            long endLong = Long.parseLong(value1.get(1).toString());
            // 日期字段的动态值比较区间为左闭右开
            flag = valueLong >= startLong && valueLong < endLong;
        } catch (NumberFormatException e) {
            flag = false;
        }
        return flag;
    }

    /**
     * 小于
     * @param value
     * @param target
     * @return
     */
    private boolean lessThan(Object value, Object target) throws Exception {
        if(value == null) {
            return false;
        }
        if (target == null) {
            target = 0;
        }
        value = unlockScientificNotation(value);
        target = unlockScientificNotation(target);
        return ((Boolean)functionService.expressRun(value +"<" + target, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY))).booleanValue();
    }

    /**
     * 小于等于
     * @param value
     * @param target
     * @return
     */
    public boolean lessEqual(Object value, Object target) throws Exception {
        if(value == null) {
            return false;
        }
        if (target == null) {
            target = 0;
        }
        value = unlockScientificNotation(value);
        target = unlockScientificNotation(target);
        return ((Boolean)functionService.expressRun(value +"<=" +target, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY))).booleanValue();
    }

    /**
     * 大于
     * @param value
     * @param target
     * @return
     */
    public boolean greaterThan(Object value, Object target) throws Exception {
        if(value == null) {
            return false;
        }
        if (target == null) {
            target = 0;
        }
        value = unlockScientificNotation(value);
        target = unlockScientificNotation(target);
        return ((Boolean)functionService.expressRun(value +">" +target, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY))).booleanValue();
    }

    /**
     * 大于等于
     * @param value
     * @param target
     * @return
     */
    public boolean greaterEqual(Object value, Object target) throws Exception {
        if(value == null) {
            return false;
        }
        if (target == null) {
            target = 0;
        }
        value = unlockScientificNotation(value);
        target = unlockScientificNotation(target);

        Object result = functionService.expressRun(value +">=" +target, new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY));
        return ((Boolean) result).booleanValue();
    }

    /**
     * 不等于任意一个
     * @param value
     * @param list
     * @return
     */
    private boolean noIn(Object value, List<Object> list) throws Exception {
        for (Object str: list) {
            if (equals(value, str)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 全部包含
     * @param value
     * @param list
     * @return
     */
    private boolean allInclude(Object value, List<Object> list) {
        for (Object str: list) {
            if (!value.toString().contains(str.toString())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 等于任意一个
     * @param value
     * @param list
     * @return
     */
    private boolean in(Object value, List<Object> list) throws Exception {
        for (Object str: list) {
            if (equals(value, str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 解开科学计数法
     * @param value
     * @return
     */
    public static String unlockScientificNotation( Object value) {
        if (value == null) {
            return null;
        }
        if (value instanceof Double || value instanceof Float) {
           DecimalFormat decimalFormat = new DecimalFormat("#.######");
           return decimalFormat.format(value);
        }
        return String.valueOf(value);
    }
}
